嗨我是k66,承上篇實作OinkBL.c,因最初前兩篇的寫法會遇到出現Bmp顏色、位置出現異常,故當時改成今日的做法—ConvertBmpToBlt()後終於能正常顯示Logo.bmp!程式碼連結
本篇與前篇做出區別,介紹ConvertBmpToBlt()這個自訂義function,僅需紀錄記憶體位置(起始處及BufferSize,以推估終點處),就可以將Bmp轉至Blt。
EFI_STATUS ConvertBmpToBlt(VOID *BmpImage, UINTN BmpImageSize, VOID **GopBlt, UINTN *GopBltSize, UINTN *PixelHeight, UINTN *PixelWidth)
{
UINT8 *ImageData;
UINT8 *ImageBegin;
BMP_IMAGE_HEADER *BmpHeader;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
UINT64 BltBufferSize;
UINTN Height;
UINTN Width;
UINTN ImageIndex;
BmpHeader = (BMP_IMAGE_HEADER *)BmpImage;
ImageBegin = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset;
/* Bmp僅支援24位元或32位元,非者即非Bmp */
if (BmpHeader->BitPerPixel != 24 && BmpHeader->BitPerPixel != 32)
return EFI_UNSUPPORTED;
BltBufferSize = BmpHeader->PixelWidth * BmpHeader->PixelHeight * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
*GopBltSize = (UINTN)BltBufferSize;
*GopBlt = AllocatePool(*GopBltSize);
*PixelWidth = BmpHeader->PixelWidth;
*PixelHeight = BmpHeader->PixelHeight;
ImageData = ImageBegin;
BltBuffer = *GopBlt;
for (Height = 0; Height < BmpHeader->PixelHeight; Height++)
{
// Buffer大小=長x寬
Blt = &BltBuffer[(BmpHeader->PixelHeight-Height-1) * BmpHeader->PixelWidth];
for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Blt++)
{
Blt->Blue = *ImageData++;
Blt->Green = *ImageData++;
Blt->Red = *ImageData++;
/* 僅會有24位元或32位元,
因為非者已在前面被return,若32位元則ImageData++。
*/
switch (BmpHeader->BitPerPixel)
{
case 24:
break;
case 32:
ImageData++;
break;
default:
break;
}
}
ImageIndex = (UINTN)(ImageData - ImageBegin);
/* 除以4後,將商+餘數 */
if ((ImageIndex % 4) != 0)
ImageData = ImageData + (4 - (ImageIndex % 4));
}
return EFI_SUCCESS;
} return Status;
關於Logo.bmp的顯示告一段落,接下來我們會實作Day11介紹的其他功能(輸出版號、Logo模式、時間,按B進入Boot Menu、按S進入SETUP、按ESC關機等)。在實作同時也會介紹相應知識。我們明天見!
實作Logo.bmp比我預期花更多時間,因此花了5篇篇幅(Day13-Day17)。其中Day16與Day17各提供一種可行的方法,供讀者參考。